﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using RSCore.Helper.Collection;
using RSEngine.Math;

namespace RSEngine.Core
{

    sealed public class Vertex
    {

        #region Variables

        /// <summary>
        /// The vertex coordinate
        /// </summary>
        public Vector3 Coordinate;

        /// <summary>
        /// The vertex normal.
        /// </summary>
        public Vector3 Normal;
        
        /// <summary>
        /// Texture coordinate.
        /// </summary>
        public Vector3 TexCoordinate;

        /// <summary>
        /// The index of this vertex in the mesh.
        /// </summary>
        public int IndexInMesh;

        public UnicityList<Edge> Edges;
        public UnicityList<Face> Faces;

        /// <summary>
        /// Geodesic distance.
        /// </summary>
        public double Distance;

        // Used for the creation of a path.
        public Vertex Next;


        //---------------

        // weights for parameterisation
        // per vertex, so that weights on opposite
        // ends of an edge can differ
        public double[] wij;
        public int label;
        //vertex normal (may also be used for other purposes)
        public Vector3 n;

        #endregion

        #region Constructor

        public Vertex()
        {
            label = 0;
            IndexInMesh = 0;
            Distance = 1e15;
            Next = null;
            Edges = new UnicityList<Edge>();
            Faces = new UnicityList<Face>();
            Normal = new Vector3();
            TexCoordinate = new Vector3();
            n = new Vector3();
            Coordinate = new Vector3();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Returns true if the edge is a mesh boundary.
        /// </summary>
        public bool IsBoundary()
        {
            for (int index = 0; index < Edges.Count; index++)
                if (Edges[index].IsBoundary)
                    return true;

            return false;
        }

        #endregion

        #region UpdateNormal

        public void UpdateNormal()
        {
            Normal = new Vector3(0, 0, 0);
            for (int i = 0; i < Faces.Count; i++)
                Normal += Faces[i].Normal;

            Normal.Normalize();
        }

        #endregion

        #region IsAdjacent

        /// <summary>
        /// Tell if the vertex is adjacent to this one.
        /// </summary>
        public bool IsAdjacent(Vertex vertex)
        {
            int i;
            for (i = 0; i < Edges.Count; i++)
            {
                if (Edges[i].Vertices[0] == vertex) return true;
                if (Edges[i].Vertices[1] == vertex) return true;
            }
            return false;
        }

        #endregion

        #region Clone

        public Vertex Clone()
        {
            Vertex v = new Vertex();

            v.Distance = Distance;
            v.Faces = Faces.Clone();
            v.label = label;
            v.n = (Vector3)n.Clone();
            v.Normal = (Vector3)Normal.Clone();
            v.Next = Next;
            v.IndexInMesh = IndexInMesh;
            v.TexCoordinate = (Vector3)TexCoordinate.Clone();
            v.Coordinate = (Vector3)this.Coordinate.Clone();
            v.wij = null;

            return v;
        }

        #endregion

        #region Misc

        public override bool Equals(object o)
        {
            return (this == o);
        }

        #endregion

    }
}
